﻿

using CSRedis;
using Microsoft.Extensions.Caching.Distributed;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace NetCore.Cache
{
    public class RedisService : ICacheService, IDisposable
    {
        private CSRedisClient _csredisCache;
        private static RedisService _instance;
        public static RedisService Instance
        {
            get
            {
                if (_instance == null)
                {
                    //new MemoryCache(Options.Create(new MemoryCacheOptions()))
                    _instance = new RedisService(ApplicationEnvironments.Site.Redis.DataBase);
                }
                return _instance;
            }
        }
        /// <summary>
        /// 过期时间 秒
        /// </summary>
        public TimeSpan ExpireTime
        {
            get
            {
                return TimeSpan.FromMinutes(ApplicationEnvironments.Site.SessionTimeout);
            }
        }
        public RedisService(int database)
        {
            _csredisCache = new CSRedisClient(ApplicationEnvironments.Site.Redis.Connection+",defaultDatabase="+ database + ",poolsize=10,ssl=false,writeBuffer=10240,prefix="+ ApplicationEnvironments.Site.Redis.InstanceName);
            
        }
        public bool Add(string key, object value)
        {
            return this.Add(key,value,ExpireTime);
        }
        /// <summary>
        /// 添加缓存
        /// </summary>
        /// <param name="key">缓存Key</param>
        /// <param name="value">缓存Value</param>
        /// <param name="expiresSliding">滑动过期时长（如果在过期时间内有操作，则以当前时间点延长过期时间,Redis中无效）</param>
        /// <param name="expiressAbsoulte">绝对过期时长</param>
        /// <returns></returns>
        public bool Add(string key, object value, TimeSpan expiresSliding, TimeSpan expiressAbsoulte)
        {
            return _csredisCache.Set(key, JSONHelper.ToJson(value), expiresSliding.Minutes * 60);
        }

        public bool Add(string key, object value, TimeSpan expiresIn, bool isSliding = false)
        {
            return _csredisCache.Set(key, JSONHelper.ToJson(value), expiresIn.Minutes*60); ;
        }

        public Task<bool> AddAsync(string key, object value)
        {
            return _csredisCache.SetAsync(key,JSONHelper.ToJson(value));
        }

        public Task<bool> AddAsync(string key, object value, TimeSpan expiresSliding, TimeSpan expiressAbsoulte)
        {
            return _csredisCache.SetAsync(key,JSONHelper.ToJson(value), expiresSliding.Minutes * 60);
        }

        public Task<bool> AddAsync(string key, object value, TimeSpan expiresIn, bool isSliding = false)
        {
            return _csredisCache.SetAsync(key,JSONHelper.ToJson(value), expiresIn.Minutes * 60);
        }

        public bool Clear()
        {
            foreach (var key in _csredisCache.Keys("*"))
            {
                _csredisCache.Del(key);
            }
            foreach (var key in _csredisCache.HKeys("*"))
            {
                _csredisCache.HKeys(key);
            }
            return true;
        }

        public void Dispose()
        {
            GC.SuppressFinalize(this);
        }

        public bool Exists(string key)
        {
            return _csredisCache.Exists(key);
        }

        public Task<bool> ExistsAsync(string key)
        {
            return _csredisCache.ExistsAsync(key);
        }

        public byte[] Get(string key)
        {
            if (this.Exists(key))
            {
                return _csredisCache.Get<byte[]>(key);
            }
            return null;
        }

        public IDictionary<string, object> GetAll(List<string> keys)
        {
            if (keys == null)
            {
                throw new ArgumentNullException(nameof(keys));
            }
            var dict = new Dictionary<string, object>();

            keys.ToList().ForEach(item => dict.Add(item, GetCache(item)));

            return dict;
        }

        public Task<IDictionary<string, object>> GetAllAsync(List<string> keys)
        {
            throw new NotImplementedException();
        }

        public Task<byte[]> GetAsync(string key, CancellationToken token = default(CancellationToken))
        {
            if (this.Exists(key))
            {
                return _csredisCache.GetAsync<byte[]>(key);
            }
            return null;
        }

        public T GetCache<T>(string key) where T : class, new()
        {
            return _csredisCache.Get<T>(key);
        }

        public object GetCache(string key)
        {
            var value = _csredisCache.Get(key);
            if (!string.IsNullOrWhiteSpace(value))
            {
                return JsonConvert.DeserializeObject(value);
            }

            return null;
        }

        public Task<T> GetCacheAsync<T>(string key) where T : class, new()
        {
            return _csredisCache.GetAsync<T>(key);
        }

        public Task<T> GetCacheAsync<T>(string key, Func<T> acquire) where T : class, new()
        {
            return _csredisCache.GetAsync<T>(key);
        }

        public Task<object> GetCacheAsync(string key)
        {
            return Task.Factory.StartNew(() => { return this.GetCache(key); });
        }

        public T GetOrCreate<T>(string key, Func<T> acquire) where T : class, new()
        {
            if (key == null)
            {
                throw new ArgumentNullException(nameof(key));
            }
            if (this.Exists(key))
            {
                var value = _csredisCache.Get(key);
                if (string.IsNullOrWhiteSpace(value))
                {
                    return default(T);
                }
                return JsonConvert.DeserializeObject<T>(value);
            }
            var result = acquire();
            this.Add(key, result);
            return result;
        }

        public T GetOrCreate<T>(string key, Func<T> acquire, bool isSliding) where T : class, new()
        {
            if (key == null)
            {
                throw new ArgumentNullException(nameof(key));
            }
            if (this.Exists(key))
            {
                var value = _csredisCache.Get(key);
                if (string.IsNullOrWhiteSpace(value))
                {
                    return default(T);
                }
                return JsonConvert.DeserializeObject<T>(value);
            }
            var result = acquire();
            if (result == null)
            {
                return result;
            }
            this.Add(key, result, TimeSpan.FromMinutes(ApplicationEnvironments.Site.SessionTimeout), isSliding);
            return result;
        }

        public void Refresh(string key)
        {
            if (Exists(key))
            {
                this.Set(key, Get(key), new DistributedCacheEntryOptions()
                {
                    SlidingExpiration = this.ExpireTime
                });
            }
        }

        public Task RefreshAsync(string key, CancellationToken token = default(CancellationToken))
        {
            return Task.Factory.StartNew(() =>
            {
                this.Refresh(key);
            });
        }

        public void Remove(string key)
        {
            _csredisCache.Del(key);
        }

        public void RemoveAll(List<string> keys)
        {
            _csredisCache.Del(keys.ToArray());
        }

        public Task RemoveAllAsync(List<string> keys)
        {
            return  _csredisCache.DelAsync(keys.ToArray());
        }

        public Task RemoveAsync(string key, CancellationToken token = default(CancellationToken))
        {
            return _csredisCache.DelAsync(key);
        }

        public bool RemoveCache(string key)
        {
           long count= _csredisCache.Del(key);
            return count > 0;
        }

        public Task<bool> RemoveCacheAsync(string key)
        {
           return Task.Factory.StartNew<bool>(() => {
               return this.RemoveCache(key);
             
            });
           
        }

        public void Set(string key, byte[] value, DistributedCacheEntryOptions options)
        {
            if (value == null)
            {
                return;
            }
            _csredisCache.Set(key,value, options.SlidingExpiration.Value.Minutes*60);
        }

        public Task SetAsync(string key, byte[] value, DistributedCacheEntryOptions options, CancellationToken token = default(CancellationToken))
        {
            return _csredisCache.SetAsync(key, value, options.SlidingExpiration.Value.Minutes * 60);

        }
    }
}
//namespace NetCore.Cache
//{
//    public class RedisService : RedisHelper,ICacheService, IDisposable
//    {
//        protected IDatabase _cache;

//        private ConnectionMultiplexer _connection;

//        private readonly string _dbinstance;


//        public TimeSpan ExpireTime
//        {
//            get {
//                return TimeSpan.FromMinutes(ApplicationEnvironments.Site.SessionTimeout);
//            }
//        }
//        private int _database ;
//        /// <summary>
//        /// 初始化连接
//        /// </summary>
//        /// <param name="dataBase">缓存构建</param>
//        public RedisService(int dataBase=0)
//        {
//            _database = dataBase;

//            //ConfigurationOptions config = new ConfigurationOptions
//            //{
//            //    EndPoints =
//            //    {
//            //        { "redis0", 6380 },
//            //        { "redis1", 6380 },
//            //        { "redis2",6380 }
//            //    },
//            //     CommandMap = CommandMap.Create(ApplicationEnvironments.Site.Redis.CommandMap, available: false),
//            //    KeepAlive = ApplicationEnvironments.Site.Redis.KeepAlive,
//            //    DefaultVersion = new Version(2, 8, 8),
//            //    Password = ApplicationEnvironments.Site.Redis.Password
//            //};
//            _connection = ConnectionMultiplexer.Connect(ApplicationEnvironments.Site.Redis.Connection);
//            _cache = _connection.GetDatabase(_database);
//            _dbinstance = ApplicationEnvironments.Site.Redis.InstanceName;
//        }

//        public static IConnectionMultiplexer GetMultiplexer()
//        {
//            return ConnectionMultiplexer.Connect(ApplicationEnvironments.Site.Redis.Connection);
//        }

//        public string GetKeyForRedis(string key)
//        {
//            return _dbinstance + key;
//        }
//        #region add
//        /// <summary>
//        /// 添加缓存
//        /// </summary>
//        /// <param name="key">缓存Key</param>
//        /// <param name="value">缓存Value</param>
//        /// <returns></returns>
//        public bool Add(string key, object value)
//        {
//            return this.Add(key, value, ExpireTime);
//        }
//        /// <summary>
//        /// 添加缓存
//        /// </summary>
//        /// <param name="key">缓存Key</param>
//        /// <param name="value">缓存Value</param>
//        /// <param name="expiresSliding">滑动过期时长（如果在过期时间内有操作，则以当前时间点延长过期时间,Redis中无效）</param>
//        /// <param name="expiressAbsoulte">绝对过期时长</param>
//        /// <returns></returns>
//        public bool Add(string key, object value, TimeSpan expiresSliding, TimeSpan expiressAbsoulte)
//        {
//            if (key == null)
//            {
//                throw new ArgumentNullException(nameof(key));
//            }
//            if (value == null)
//            {
//                return true;
//            }
//            return _cache.StringSet(GetKeyForRedis(key), Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(value)), expiressAbsoulte);
//        }
//        /// <summary>
//        /// 添加缓存
//        /// </summary>
//        /// <param name="key">缓存Key</param>
//        /// <param name="value">缓存Value</param>
//        /// <param name="expiresIn">缓存时长</param>
//        /// <param name="isSliding">是否滑动过期（如果在过期时间内有操作，则以当前时间点延长过期时间,Redis中无效）</param>
//        /// <returns></returns>
//        public bool Add(string key, object value, TimeSpan expiresIn, bool isSliding = false)
//        {
//            if (key == null)
//            {
//                throw new ArgumentNullException(nameof(key));
//            }
//            if (value == null)
//            {
//                return true;
//            }
//            return _cache.StringSet(GetKeyForRedis(key), Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(value)), expiresIn);
//        }

//        public Task<bool> AddAsync(string key, object value)
//        {
//            return Task.Factory.StartNew<bool>(() => { return this.Add(key, value); });
//        }

//        public Task<bool> AddAsync(string key, object value, TimeSpan expiresSliding, TimeSpan expiressAbsoulte)
//        {
//            return Task.Factory.StartNew<bool>(() => { return this.Add(key, value, expiresSliding, expiressAbsoulte); });
//        }

//        public Task<bool> AddAsync(string key, object value, TimeSpan expiresIn, bool isSliding = false)
//        {
//            return Task.Factory.StartNew<bool>(() => { return this.Add(key, value, expiresIn, isSliding); });
//        }
//        #endregion

//        #region 验证是否存在
//        /// <summary>
//        /// 验证缓存项是否存在
//        /// </summary>
//        /// <param name="key">缓存Key</param>
//        /// <returns></returns>
//        public bool Exists(string key)
//        {
//            if (string.IsNullOrWhiteSpace(key))
//            {
//                throw new ArgumentNullException(nameof(key));
//            }
//            return _cache.KeyExists(GetKeyForRedis(key));
//        }

//        public Task<bool> ExistsAsync(string key)
//        {
//            //if (key == null)
//            //{
//            //    throw new ArgumentNullException(nameof(key));
//            //}
//            //object cached;
//            // bool flag=_cache.TryGetValue(key, out cached);
//            return Task.Factory.StartNew<bool>(() => { return this.Exists(key); });
//        }
//        #endregion

//        #region Get
//        /// <summary>
//        /// 获取缓存
//        /// </summary>
//        /// <param name="key">缓存Key</param>
//        /// <returns></returns>
//        public T GetCache<T>(string key) where T : class, new()
//        {
//            if (key == null)
//            {
//                throw new ArgumentNullException(nameof(key));
//            }

//            var value = _cache.StringGet(GetKeyForRedis(key));

//            if (!value.HasValue)
//            {
//                return default(T);
//            }

//            return JsonConvert.DeserializeObject<T>(value);
//        }

//        public T GetOrCreate<T>(string key, Func<T> acquire) where T : class, new()
//        {
//            if (key == null)
//            {
//                throw new ArgumentNullException(nameof(key));
//            }
//            if (this.Exists(key))
//            {
//                var value = _cache.StringGet(GetKeyForRedis(key));
//                if (!value.HasValue)
//                {
//                    return default(T);
//                }

//                return JsonConvert.DeserializeObject<T>(value);
//            }
//            var result = acquire();
//            this.Add(key, result);
//            return result;

//        }
//        public T GetOrCreate<T>(string key, Func<T> acquire, bool isSliding ) where T : class, new()
//        {
//            if (key == null)
//            {
//                throw new ArgumentNullException(nameof(key));
//            }
//            if (this.Exists(key))
//            {
//                var value = _cache.StringGet(GetKeyForRedis(key));
//                if (!value.HasValue)
//                {
//                    return default(T);
//                }

//                return JsonConvert.DeserializeObject<T>(value);
//            }
//            var result = acquire();
//            if (result == null)
//            {
//                return result;
//            }
//            this.Add(key, result, TimeSpan.FromMinutes(ApplicationEnvironments.Site.SessionTimeout), isSliding);
//            return result;

//        }
//        /// <summary>
//        /// 获取缓存
//        /// </summary>
//        /// <param name="key">缓存Key</param>
//        /// <returns></returns>
//        public object GetCache(string key)
//        {
//            if (key == null)
//            {
//                throw new ArgumentNullException(nameof(key));
//            }

//            var value = _cache.StringGet(GetKeyForRedis(key));

//            if (!value.HasValue)
//            {
//                return null;
//            }
//            return JsonConvert.DeserializeObject(value);
//        }
//        /// <summary>
//        /// 获取缓存集合
//        /// </summary>
//        /// <param name="keys">缓存Key集合</param>
//        /// <returns></returns>
//        public IDictionary<string, object> GetAll(List<string> keys)
//        {
//            if (keys == null)
//            {
//                throw new ArgumentNullException(nameof(keys));
//            }
//            var dict = new Dictionary<string, object>();

//            keys.ToList().ForEach(item => dict.Add(item, GetCache(GetKeyForRedis(item))));

//            return dict;
//        }



//        public Task<IDictionary<string, object>> GetAllAsync(List<string> keys)
//        {
//            return Task.Factory.StartNew<IDictionary<string, object>>(() => { return this.GetAll(keys); });
//        }

//        public Task<T> GetCacheAsync<T>(string key) where T : class, new()
//        {
//            return Task.Factory.StartNew<T>(() => { return this.GetCache<T>(key); });
//        }
//        public Task<T> GetCacheAsync<T>(string key, Func<T> acquire) where T : class, new()
//        {
//            return Task.Factory.StartNew<T>(() => { return this.GetOrCreate<T>(key, acquire); });
//        }

//        public Task<object> GetCacheAsync(string key)
//        {
//            return Task.Factory.StartNew(() => { return this.GetCache(key); });
//        }
//        #endregion

//        #region Remove
//        /// <summary>
//        /// 删除缓存
//        /// </summary>
//        /// <param name="key">缓存Key</param>
//        /// <returns></returns>
//        public bool RemoveCache(string key)
//        {
//            if (key == null)
//            {
//                throw new ArgumentNullException(nameof(key));
//            }
//            return _cache.KeyDelete(GetKeyForRedis(key));
//        }
//        /// <summary>
//        /// 批量删除缓存
//        /// </summary>
//        /// <param name="key">缓存Key集合</param>
//        /// <returns></returns>
//        public void RemoveAll(List<string> keys)
//        {
//            if (keys == null)
//            {
//                throw new ArgumentNullException(nameof(keys));
//            }

//            keys.ForEach(item => RemoveCache(item));
//        }
//        public Task RemoveAllAsync(List<string> keys)
//        {
//            return Task.Factory.StartNew(() => { this.RemoveAll(keys); });
//        }

//        public Task<bool> RemoveCacheAsync(string key)
//        {
//            return Task.Factory.StartNew<bool>(() => { return this.RemoveCache(key); });
//        }
//        #endregion





//        public void Dispose()
//        {
//            if (_cache != null)
//                _connection.Dispose();
//            GC.SuppressFinalize(this);
//        }

//        public bool Clear()
//        {
//            var keys = new List<string>();
//            //遍历集群内服务器
//            foreach (var endPoint in _connection.GetEndPoints())
//            {
//                //获取指定服务器
//                var server = _connection.GetServer(endPoint);
//                //在指定服务器上使用 keys 或者 scan 命令来遍历key
//                //server.FlushDatabase();
//                foreach (var key in server.Keys(_database))
//                {
//                    //获取key对于的值
//                    keys.Add(key);
//                    _cache.KeyDelete(key);
//                }
//            }
//           this.RemoveAll(keys);
//            return true;
//        }


//        public byte[] Get(string key)
//        {
//            var value = _cache.StringGet(GetKeyForRedis(key));
//            if (!value.HasValue)
//            {
//                return null;
//            }
//            return value;
//        }

//        public Task<byte[]> GetAsync(string key, CancellationToken token = default(CancellationToken))
//        {
//            return Task.Factory.StartNew<byte[]>(() => {

//                return this.Get(key);
//            });
//        }

//        public void Set(string key, byte[] value, DistributedCacheEntryOptions options)
//        {
//            _cache.StringSet(GetKeyForRedis(key), value, options.SlidingExpiration.HasValue ? options.SlidingExpiration.Value : this.ExpireTime);
//          //  this.Add(key, Convert.ToBase64String(value), options.SlidingExpiration.HasValue ? options.SlidingExpiration.Value : this.ExpireTime);
//        }

//        public Task SetAsync(string key, byte[] value, DistributedCacheEntryOptions options, CancellationToken token = default(CancellationToken))
//        {
//            return Task.Factory.StartNew(() => {

//                this.Set(key, value, options);
//            });
//        }

//        public void Refresh(string key)
//        {
//            if (Exists(key))
//            {
//                this.Set(key, Get(key),new DistributedCacheEntryOptions() {
//                 SlidingExpiration=this.ExpireTime
//                });
//            }
//        }

//        public Task RefreshAsync(string key, CancellationToken token = default(CancellationToken))
//        {
//            return Task.Factory.StartNew(() => {
//                this.Add(key, Get(key));
//            });
//        }

//        public void Remove(string key)
//        {
//            this.SessionRemove(key);
//        }

//        public Task RemoveAsync(string key, CancellationToken token = default(CancellationToken))
//        {
//            return Task.Factory.StartNew(() => {
//                this.SessionRemove(key);
//            });
//        }

//        /// <summary>
//        /// 删除缓存
//        /// </summary>
//        /// <param name="key">缓存Key</param>
//        /// <returns></returns>
//        public bool SessionRemove(string key)
//        {
//            if (key == null)
//            {
//                throw new ArgumentNullException(nameof(key));
//            }
//            return _cache.KeyDelete(GetKeyForRedis(key));
//        }
//    }
//}
